/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2022-2023. All rights reserved.
 */

package service

import (
	"bytes"
	"crypto/tls"
	"io/ioutil"
	"net/http"
	"prim-server/common"
	"prim-server/dao"
	"prim-server/logger"
	"prim-server/util"
	"time"

	"github.com/gomodule/redigo/redis"
	"github.com/pkg/errors"
	"github.com/spf13/cast"
)

const (
	RedisPhoneId               = "#redisPhoneNumId"
	RedisPhoneVerExpireTimeMin = 60
	AUTH_HEADER_VALUE          = "WSSE realm=\"SDP\",profile=\"UsernameToken\",type=\"Appkey\""
	RegionNum                  = "+86"
	MaxTry                     = 5
)

func postToSendSMS(url string, param []byte, headers map[string]string) (string, error) {
	tr := &http.Transport{
		TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
	}
	client := &http.Client{Transport: tr}

	req, err := http.NewRequest("POST", url, bytes.NewBuffer(param))
	if err != nil {
		return "", err
	}
	for key, header := range headers {
		req.Header.Set(key, header)
	}

	resp, err := client.Do(req)
	if err != nil {
		return "", err
	}
	defer resp.Body.Close()
	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return "", err
	}
	return string(body), nil
}

func SendVerificationCodeBySMS(phoneNum, verificationCode string) error {
	return nil
}

func CheckPhoneNumUsed(phoneNumber string) (bool, error) {
	queryParamenter := common.QueryUserDetail{
		PhoneNumber: []string{phoneNumber},
	}
	user, _, err := GetUserAllWithQueryParameter(&queryParamenter)
	if err != nil {
		logger.Error("get user error: %v, phone: %s", err.Error(), phoneNumber)
		return true, err
	}
	if len(user) > 0 {
		return true, nil
	}
	return false, nil
}
func UpdatePhoneNumber(userId string, phoneNumber string) error {
	updateUserParameters := common.ModifyUserDetail{
		UserId:      userId,
		PhoneNumber: &phoneNumber,
	}
	err := dao.GetUserDao().UpdateAllUserInfo(&updateUserParameters)
	if err != nil {
		return err
	}
	return nil
}

// WritePhoneVerCodeIntoRedis
func WritePhoneVerCodeIntoRedis(phoneNum string, phi *common.PhoneVerificationInfo, redisPool *redis.Pool) error {
	if redisPool == nil {
		return errors.Errorf("can't connect redis")
	}
	//将手机验证码信息手上写入redis
	conn := redisPool.Get()
	defer conn.Close()
	//该订单对应的key
	keyOfPhone := util.CombineTwoString(phoneNum, RedisPhoneId)
	valueOfOrder, err := util.BuildPhoneVerificationValueForRedis(phi)
	if err != nil {
		return err
	}
	_, err = conn.Do("SET", keyOfPhone, valueOfOrder)
	if err != nil {
		return err
	}
	_, err = conn.Do("expire", keyOfPhone, util.VerCodeExpireTimeMinute*RedisPhoneVerExpireTimeMin)
	if err != nil {
		return err
	}
	return nil
}

// GetPhoneVerificationFromRedis 查
func GetPhoneVerificationFromRedis(phoneNum string, redisPool *redis.Pool) (verInfo *common.PhoneVerificationInfo, err error) {
	if redisPool == nil {
		return nil, errors.Errorf("Cannot connect redis")
	}
	conn := redisPool.Get()
	defer conn.Close()
	keyOfPhone := util.CombineTwoString(phoneNum, RedisPhoneId)
	valueOfPhone, err := conn.Do("GET", keyOfPhone)
	if err != nil {
		logger.Error("get phone error: %v, phone: %s", err.Error(), phoneNum)
		return nil, err
	}
	if valueOfPhone == nil {
		return nil, nil
	}
	verInfo, err = util.GetPhoneVerificationFromRedisValue(cast.ToString(valueOfPhone))
	if err != nil {
		logger.Error("get phone error: %v, phone: %s", err.Error(), phoneNum)
		return nil, err
	}
	return verInfo, nil
}

// CompareVerificationCodeInRedis 比较redis里的验证码和当前验证码
func CompareVerificationCodeInRedis(phoneNum, inputVerificationCode string, redisPool *redis.Pool) (matching, exists bool, err error) {
	verInfo, err := GetPhoneVerificationFromRedis(phoneNum, redisPool)
	if err != nil {
		return false, false, err
	}
	if verInfo == nil {
		return false, false, nil
	}
	currentTimeUnix := time.Now().Unix()
	if currentTimeUnix > verInfo.ExpireTime {
		return false, false, nil
	}
	if verInfo.Code != inputVerificationCode {
		return false, true, nil
	}
	return true, true, nil
}

// DeletePhoneVerCodeInRedis 删
func DeletePhoneVerCodeInRedis(phoneNum string, redisPool *redis.Pool) (err error) {
	if redisPool == nil {
		return errors.Errorf("can't connect redis")
	}
	conn := redisPool.Get()
	defer conn.Close()
	keyOfPhone := util.CombineTwoString(phoneNum, RedisPhoneId)
	_, err = conn.Do("DEL", keyOfPhone)
	if err != nil {
		return errors.Errorf("Failed to delete value from redis error: %v", err)
	}
	return nil
}

func UpdatePhoneVerifyFailTimes(phoneNum string, redisPool *redis.Pool) (err error) {
	if redisPool == nil {
		return errors.Errorf("can't connect redis")
	}
	conn := redisPool.Get()
	defer conn.Close()
	verInfo, err := GetPhoneVerificationFromRedis(phoneNum, redisPool)
	if err != nil {
		return errors.Errorf("Fail to update Update Verification FailTimes : %v", err)
	}
	verInfo.FailTimes += 1
	if verInfo.FailTimes >= MaxTry {
		err = DeletePhoneVerCodeInRedis(phoneNum, redisPool)
		if err != nil {
			return errors.Errorf("Fail to update Update Verification FailTimes : %v", err)
		}
		return nil
	}
	err = WritePhoneVerCodeIntoRedis(phoneNum, verInfo, redisPool)
	if err != nil {
		return errors.Errorf("Fail to update Update Verification FailTimes : %v", err)
	}
	return nil
}

func CheckPhoneNumRegByID(userId string) (bool, error) {
	userInfo, err := GetUserOneWithUserId(userId)
	if err != nil {
		return false, err
	}
	if userInfo == nil {
		return false, errors.Errorf("Fail to find userInfo in CheckPhoneNumRegByID : %v", err)
	}
	if userInfo.PhoneNumber == "" {
		return false, nil
	}
	return true, nil
}
